import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
import { DefaultStage } from "../default-stage";
import { Model } from "./model";
import { Helper } from "babylon-lib/tool/helper";
import { RawAssetsName } from "../../raw-assets-info";
import { Quaternion, Vector3 } from "@babylonjs/core/Maths/math.vector";
import { Axis } from "@babylonjs/core/Maths/math.axis";
import { AnimationFrame, ITimer } from "babylon-lib/index";
import { State } from 'babylon-lib/misc/state';
import { Bomb } from './bomb';
import { CreateUINode } from "babylon-lib/gui/base/ui-node";
import { CreateUIText } from "babylon-lib/gui/control/ui-text";
import { ANCHOR } from "babylon-lib/gui/control/abstract-base";
import { RenderOrder } from "babylon-lib/misc/render-order";
import * as Data from '../../data/data';
import { Landscape } from "./landscape";
import { WebXRCamera } from "@babylonjs/core";


enum STATE {
    RIGHT_BOMB_IN_PLACE,
    RIGHT_BOMB_DROP,
    RIGHT_BOMB_DESTROY,
    LEFT_BOMB_IN_PLACE,
    LEFT_BOMB_DROP,
    LEFT_BOMB_DESTROY,
    RELOADING,
};

class UAV {

    private static _container: TransformNode;
    private static _bombRight: Bomb;
    private static _bombLeft: Bomb;
    private static _bindReq: ITimer = {};
    private static _sampleReq = {};
    private static _reloadReq = {};
    private static _state = new State(STATE.RIGHT_BOMB_IN_PLACE, STATE.LEFT_BOMB_IN_PLACE);
    private static _reloadTime = 30000;
    private static _count = 0;
    private static _countReq = {};

    public static inertia = new Vector3();

    public static initialize(stage: DefaultStage): void {
        this._container = new TransformNode('uav-container', stage.mainScene);
        this._container.rotationQuaternion = Quaternion.Identity();
        this.setModel(stage);
        this.bindToCamera(stage);
        this.initializeMark(stage);
        this.sampling(stage);
        Data.lifeNumber.value = 1;
    }

    public static get container(): TransformNode {
        return this._container;
    }

    public static dropBomb(): void {
        if (this._state.exist(STATE.RIGHT_BOMB_IN_PLACE)) {
            this._state.remove(STATE.RIGHT_BOMB_IN_PLACE);
            this._bombRight.mount(false);
            this._state.add(STATE.RIGHT_BOMB_DROP);
        } else if (this._state.exist(STATE.LEFT_BOMB_IN_PLACE)) {
            this._state.remove(STATE.LEFT_BOMB_IN_PLACE);
            this._bombLeft.mount(false);
            this._state.add(STATE.LEFT_BOMB_DROP);
        }
        if (this._state.notExist(STATE.RIGHT_BOMB_IN_PLACE, STATE.LEFT_BOMB_IN_PLACE, STATE.RELOADING)) {
            this._state.add(STATE.RELOADING);
            this.reload();
        }
    }

    private static reload(): void {
        AnimationFrame.cancel(this._reloadReq);
        Data.reloading.value = true;
        AnimationFrame.throttleByTime(this._reloadReq, this._reloadTime, () => {
            this._bombRight.mount(true);
            this._bombLeft.mount(true);
            this._state.remove(STATE.RIGHT_BOMB_DESTROY, STATE.RIGHT_BOMB_DROP, STATE.LEFT_BOMB_DESTROY, STATE.LEFT_BOMB_DROP, STATE.RELOADING);
            this._state.add(STATE.RIGHT_BOMB_IN_PLACE, STATE.LEFT_BOMB_IN_PLACE);
            Data.lifeNumber.value++;
            Data.reloading.value = false;
        }, false);
    }

    private static initializeMark(stage: DefaultStage): void {
        const node = CreateUINode('uav-mark-node', stage.mainScene, {
            anchor: new Vector3(0.5, 0.5, 0),
            lockToCamera: true,
        }, [
            CreateUIText('uav-mark-text', stage.mainScene, {
                text: '+',
                anchor: ANCHOR.CENTER,
                fontColor: '#ffffff',
                width: 1,
                height: 1,
                fontSize: 50,
                inoperable: true,
                renderingGroupId: RenderOrder.id(Data.orders.sceneFront),
            }),
        ]);
    }

    private static sampling(stage: DefaultStage): void {
        AnimationFrame.cancel(this._countReq);
        const _this = UAV;
        const prePos = new Vector3();
        const curPos = new Vector3();
        const ext = Landscape.zoneExtend;
        AnimationFrame.request(() => {
            curPos.copyFrom(_this._container.getAbsolutePosition());
            _this.inertia.copyFrom(curPos).subtractInPlace(prePos);
            prePos.copyFrom(curPos);
            if (curPos.x < -ext || curPos.x > ext || curPos.z < -ext || curPos.z > ext) {
                AnimationFrame.throttleByTime(_this._countReq, 1000, () => {
                    const c = 10 - _this._count;
                    Data.failedCount.value = Math.max(c, 0);
                    if (c <= 0) {
                        Data.gameOn.value = false;
                        Data.taskDone.value = false;
                    }
                    _this._count++;
                }, true);
            } else {
                _this._count = 0;
                Data.failedCount.value = 10;
            }
        }, 16, 200, this._sampleReq);
    }

    private static bindToCamera(stage: DefaultStage): void {
        const _this = UAV;
        const dir = new Vector3();
        const ref = new Vector3();
        const rot = Quaternion.Identity();

        this._bindReq.observable = stage.mainScene.onBeforeCameraRenderObservable;
        AnimationFrame.request(() => {
            const camera = (stage.mainCamera instanceof WebXRCamera) ? stage.mainCamera.rigCameras[0] : stage.mainCamera;
            _this._container.position.copyFrom(camera.position);

            Helper.cameraDirection(camera, dir);
            dir.y = 0;
            dir.normalize();
            ref.set(0, 0, 1);
            ref.applyRotationQuaternionInPlace(_this._container.rotationQuaternion!);
            ref.normalize();
            const ang = Vector3.GetAngleBetweenVectors(ref, dir, Axis.Y) * 0.01;
            Quaternion.FromEulerAnglesToRef(0, ang, 0, rot)
            _this._container.rotationQuaternion?.multiplyInPlace(rot);
        }, 0, 200, this._bindReq);

    }

    private static setModel(stage: DefaultStage): void {
        Model.wurenji.parent = this._container;
        Model.wurenji.position.set(0, 0, 0);
        Model.wurenji.scaling.set(5,5,5);

        const bombRight = new Bomb(stage, {
            name: 'bomb-right',
            model: Model.zhadan,
            mount: Helper.nodeInArray(RawAssetsName.mountRight, Model.wurenji.getChildTransformNodes(false), undefined, true)!,
        });
        this._bombRight = bombRight;

        const bombLeft = new Bomb(stage, {
            name: 'bomb-left',
            model: Model.zhadan.clone('bomb-left-model', Model.zhadan.parent)!,
            mount: Helper.nodeInArray(RawAssetsName.mountLeft, Model.wurenji.getChildTransformNodes(false), undefined, true)!,
        });
        this._bombLeft = bombLeft;

        bombRight.mount(true);
        bombLeft.mount(true);
    }

}


export { UAV };